"""
LWX平台集成服务 - 专职负责与LWX平台的交互
"""

import os
import json
import logging
import requests
import base64
from datetime import datetime
from typing import Optional, Dict, Any
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

from ..core.types import SchoolConfig, OperationResult


logger = logging.getLogger(__name__)


class LWXPlatformService:
    """LWX平台集成服务"""
    
    def __init__(self, report_url: str = None, aes_key: str = None):
        self.logger = logging.getLogger(self.__class__.__name__)
        self.report_url = report_url
        self.aes_key = aes_key
        self.report_status_file = '/tmp/mobox_last_report.txt'
    
    def report_device_info(self, device_info: Dict[str, Any], 
                          trigger_sync: bool = True) -> OperationResult:
        """
        上报设备信息到LWX平台
        
        Args:
            device_info: 设备信息字典
            trigger_sync: 是否触发后续的配置同步
            
        Returns:
            OperationResult: 操作结果，包含学校配置信息
        """
        try:
            if not self.report_url or not self.aes_key:
                return OperationResult(
                    success=False,
                    message="LWX平台配置不完整",
                    error="Missing report_url or aes_key"
                )
            
            # 转换为JSON并加密
            json_data = json.dumps(device_info)
            encrypted_data = self._encrypt_data(json_data)
            
            if not encrypted_data:
                return OperationResult(
                    success=False,
                    message="数据加密失败",
                    error="Failed to encrypt device data"
                )
            
            # 发送到LWX平台
            response_result = self._send_to_platform(encrypted_data)
            
            if not response_result.success:
                return response_result
            
            # 解析响应
            response_data = response_result.details.get('response_data', {})
            
            # 提取学校配置信息
            school_config = self._extract_school_config(response_data)
            
            # 记录上报时间
            self._mark_report_time()
            
            return OperationResult(
                success=True,
                message="设备信息上报成功",
                details={
                    "school_config": school_config,
                    "trigger_sync": trigger_sync,
                    "response_data": response_data
                }
            )
            
        except Exception as e:
            self.logger.error(f"设备信息上报失败: {e}")
            return OperationResult(
                success=False,
                message=f"设备信息上报失败: {str(e)}",
                error=str(e)
            )
    
    def get_school_config_from_response(self, response_data: Dict[str, Any]) -> Optional[SchoolConfig]:
        """从LWX平台响应中提取学校配置"""
        try:
            if not response_data or not isinstance(response_data, dict):
                return None
            
            data = response_data.get('data', {})
            if not isinstance(data, dict):
                return None
            
            school_info = data.get('school', {})
            if not school_info:
                return None
            
            # 根据新的简化架构，LWX平台返回学校名和基础镜像信息
            return SchoolConfig(
                school_id=school_info.get('id', ''),
                school_name=school_info.get('name', ''),
                base_image=school_info.get('image_version', 'mobox-python-hardware:latest')
            )
            
        except Exception as e:
            self.logger.error(f"提取学校配置失败: {e}")
            return None
    
    def should_report_on_startup(self) -> bool:
        """检查是否应该在启动时上报（距离上次上报超过12小时）"""
        try:
            if os.path.exists(self.report_status_file):
                with open(self.report_status_file, 'r') as f:
                    last_report_str = f.read().strip()
                    if last_report_str:
                        last_report_time = datetime.fromisoformat(last_report_str)
                        # 如果距离上次上报超过12小时，则需要重新上报
                        time_diff = datetime.now() - last_report_time
                        return time_diff.total_seconds() > 43200  # 12小时
            return True  # 没有记录文件或解析失败，需要上报
        except Exception as e:
            self.logger.warning(f"检查上报状态文件失败: {str(e)}，将执行上报")
            return True
    
    def collect_device_info(self) -> Optional[Dict[str, Any]]:
        """收集设备信息"""
        try:
            device_data = {
                "deviceId": self._get_device_id(),
                "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "system": {
                    "cpu_usage": self._get_cpu_usage(),
                    "memory_usage": self._get_memory_usage(),
                    "disk_usage": self._get_disk_usage(),
                    "network_info": self._get_network_info(),
                    "docker_info": self._get_docker_info(),
                    "os_version": self._get_os_version(),
                    "last_update": datetime.now().strftime("%Y-%m-%d")
                }
            }
            
            self.logger.debug(f"收集的设备数据: {device_data}")
            return device_data
            
        except Exception as e:
            self.logger.error(f"收集设备状态信息失败: {str(e)}")
            return None
    
    def _encrypt_data(self, raw_str: str) -> Optional[str]:
        """使用AES-ECB加密数据"""
        try:
            cipher = AES.new(self.aes_key.encode('utf-8'), AES.MODE_ECB)
            padded = pad(raw_str.encode('utf-8'), AES.block_size)
            encrypted_bytes = cipher.encrypt(padded)
            return base64.b64encode(encrypted_bytes).decode('utf-8')
        except Exception as e:
            self.logger.error(f"加密失败: {str(e)}")
            return None
    
    def _send_to_platform(self, encrypted_data: str) -> OperationResult:
        """发送加密数据到LWX平台"""
        try:
            headers = {
                "Content-Type": "application/x-www-form-urlencoded",
                "tenant-id": "1"
            }
            
            params = {
                "data": encrypted_data
            }
            
            response = requests.post(
                self.report_url, 
                params=params,
                headers=headers,
                timeout=10
            )
            
            self.logger.info(f"LWX平台响应状态码: {response.status_code}")
            self.logger.debug(f"LWX平台响应内容: {response.text}")
            
            if response.status_code == 200:
                try:
                    response_data = response.json()
                    if response_data.get('code') == 0:
                        return OperationResult(
                            success=True,
                            message="数据发送成功",
                            details={'response_data': response_data}
                        )
                    else:
                        return OperationResult(
                            success=False,
                            message=f"LWX平台返回错误: {response.text}",
                            error=f"Platform error: code={response_data.get('code')}"
                        )
                except Exception as e:
                    return OperationResult(
                        success=False,
                        message=f"解析响应失败: {str(e)}",
                        error=f"JSON parse error: {str(e)}"
                    )
            else:
                return OperationResult(
                    success=False,
                    message=f"HTTP请求失败: {response.status_code}",
                    error=f"HTTP {response.status_code}: {response.text}"
                )
                
        except Exception as e:
            return OperationResult(
                success=False,
                message=f"发送请求失败: {str(e)}",
                error=str(e)
            )
    
    def _extract_school_config(self, response_data: Dict[str, Any]) -> Optional[SchoolConfig]:
        """从响应中提取学校配置"""
        return self.get_school_config_from_response(response_data)
    
    def _mark_report_time(self):
        """标记上报时间"""
        try:
            with open(self.report_status_file, 'w') as f:
                f.write(datetime.now().isoformat())
        except Exception as e:
            self.logger.warning(f"标记上报时间失败: {str(e)}")
    
    def _get_device_id(self) -> str:
        """获取设备ID"""
        try:
            # 尝试从多个来源获取设备ID
            device_id = None
            
            # 方法1: 从MAC地址生成
            import uuid
            mac = hex(uuid.getnode())[2:].upper()
            if mac and mac != 'FFFFFFFFFFFF':
                device_id = f"MOBOX-{mac}"
            
            # 方法2: 从系统文件读取
            if not device_id:
                try:
                    with open('/proc/sys/kernel/hostname', 'r') as f:
                        hostname = f.read().strip()
                        if hostname:
                            device_id = f"MOBOX-{hostname}"
                except:
                    pass
            
            # 方法3: 默认值
            if not device_id:
                device_id = "MOBOX-UNKNOWN"
                
            return device_id
            
        except Exception:
            return "MOBOX-DEFAULT"
    
    def _get_cpu_usage(self) -> str:
        """获取CPU使用率"""
        try:
            import psutil
            return f"{psutil.cpu_percent():.1f}%"
        except:
            return "Unknown"
    
    def _get_memory_usage(self) -> str:
        """获取内存使用率"""
        try:
            import psutil
            memory = psutil.virtual_memory()
            return f"{memory.percent:.1f}%"
        except:
            return "Unknown"
    
    def _get_disk_usage(self) -> str:
        """获取磁盘使用率"""
        try:
            import psutil
            disk = psutil.disk_usage('/')
            return f"{disk.percent:.1f}%"
        except:
            return "Unknown"
    
    def _get_network_info(self) -> Dict[str, str]:
        """获取网络信息"""
        try:
            import psutil
            import socket
            
            # 获取IP地址
            hostname = socket.gethostname()
            ip_address = socket.gethostbyname(hostname)
            
            # 获取MAC地址
            import uuid
            mac_address = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff)
                                  for elements in range(0, 2*6, 2)][::-1])
            
            return {
                "ip_address": ip_address,
                "mac_address": mac_address,
                "hostname": hostname
            }
        except:
            return {
                "ip_address": "Unknown",
                "mac_address": "Unknown", 
                "hostname": "Unknown"
            }
    
    def _get_docker_info(self) -> Dict[str, Any]:
        """获取Docker信息"""
        try:
            import subprocess
            
            # 获取Docker版本
            version_result = subprocess.run(['docker', '--version'], 
                                         capture_output=True, text=True, timeout=5)
            docker_version = version_result.stdout.strip() if version_result.returncode == 0 else "Unknown"
            
            # 获取运行中的容器数量
            ps_result = subprocess.run(['docker', 'ps', '-q'], 
                                     capture_output=True, text=True, timeout=5)
            running_containers = len(ps_result.stdout.strip().split('\n')) if ps_result.returncode == 0 and ps_result.stdout.strip() else 0
            
            return {
                "version": docker_version,
                "running_containers": running_containers
            }
        except:
            return {
                "version": "Unknown",
                "running_containers": 0
            }
    
    def _get_os_version(self) -> str:
        """获取操作系统版本"""
        try:
            import platform
            return f"{platform.system()} {platform.release()}"
        except:
            return "Unknown"